
#ifndef _PROFILER_H_
#define _PROFILER_H_

#include "../sleipner_config.h"

#include "num/named_set.h"
#include "timer.h"

namespace util 
{
struct ProfilingGroup
{
    float		StartTime;              // When was it started ? 0 if not started this frame
    float		Accumulated;            // When it's ended, it will accumulate into this var
    float		LastFrame;              // When calculating, always stay one p
	std::string		Name;
	ProfilingGroup() 
	{ 
		Reset(); 
		LastFrame = 0;
	};
	static	void	ResetCB(ProfilingGroup* pGroup, void* pPayload)
	{
		pGroup->Reset();
	}
	void            Reset()
    {
        StartTime	= 0;
        Accumulated	= 0;
    }
};

class Profiler
{
// Enums
public:
    // static accessors
    static Profiler&                Instance();
	
	bool							IsEnabled() const { return m_IsEnabled; };
	void							SetEnabled(bool b) { m_IsEnabled = b; };

	// system functions
    void                            StartFrame();   // reset next frame
    void                            EndFrame();     // calculate last frame
    float                           GetTotalTime()         { return m_LastTotalTime; };
    float                           StampToTime(float _Time);
    void                            Reset();

    // Section code
	void                            StartSection(const std::string& _SectionID);
    void                            StopSection(const std::string&_SectionID);
    void                            AddSectionTicks(const std::string& _SectionID, float _Time);
    // Retrieve
    float                           GetSectionTime(const std::string& _SectionID);
    float                           GetSectionPercentage(const std::string& _SectionID);

	ProfilingGroup*					CreateSection(const std::string& Name);
	ProfilingGroup*					GetSection(const std::string& Name) { return m_Groups.GetElement(Name); };
	ProfilingGroup*					GetSectionByIndex(int ID) { return m_Groups.GetElementByIndex(ID); };
	unsigned int					GetSectionC() const { return m_Groups.GetElementC(); };
	
	// variables
// functions will need to access this to do rendering, etc.
// just let it for now
	num::NamedSet<ProfilingGroup*>	m_Groups;
protected:
    float							m_FrameStart;               // track total instructions spent in frame
	float							m_LastTotalTime;
    bool							m_IsEnabled;
// functions
                                    Profiler();
                                    ~Profiler();
                                    // Paranoia is an art-form....
                                    Profiler( const Profiler & );     
                                    Profiler & operator=( const Profiler & );
};


//////////////////////////////////////////////////////////////////////
/// \brief Profile Section
///
/// Use this class to provide auto-profiling of sections
///
//////////////////////////////////////////////////////////////////////
class ProfileSection
{
private:
    std::string						m_Group;
    float                   m_Start;

public:
	ProfileSection(const std::string& Group)
    {
        m_Group = Group;
        m_Start =  Timer::GetTimeStamp();
    };
    ~ProfileSection()
    {
        float End = Timer::GetTimeStamp();
        float Delta;
        Delta = End - m_Start;
        Profiler::Instance().AddSectionTicks(m_Group, Delta);
    }
};
#define _ENABLE_PROFILER
#ifdef _ENABLE_PROFILER                 
    #define START_PROFILER()                util::Profiler::Instance().StartFrame();
    #define END_PROFILER()                  util::Profiler::Instance().EndFrame();
    #define START_PROFILE_SECTION(SECTION_ID)  util::Profiler::Instance().StartSection(SECTION_ID);    
    #define STOP_PROFILE_SECTION(SECTION_ID)   util::Profiler::Instance().StopSection(SECTION_ID);
#define	PROFILE_BLOCK(SECTION_ID)			util::ProfileSection	__StartProfilerSection##__LINE__( SECTION_ID );
#else
    #define START_PROFILER()                
    #define END_PROFILER()                  
    #define START_PROFILE_SECTION(Section)     
    #define STOP_PROFILE_SECTION(Section)    
	#define	PROFILE_BLOCK(Section)
#endif

} // end namespace util

#endif // 
